package com.raph.server;

import com.raph.db.DbUser;
import com.raph.exception.PasswordErrorException;
import com.raph.exception.UserNotExistException;
import com.raph.message.Message;
import com.raph.message.MessageType;
import com.raph.user.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.SocketException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

public class ClientHandler implements Runnable{
    private final Socket socket;
    private User user;
    private static final Logger logger = LoggerFactory.getLogger(ClientHandler.class);
    private static boolean flag = true;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }


    @Override
    public void run() {
        try {
            while(flag) {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(socket.getInputStream()));
                Message message = new Message(reader.readLine());
                logger.info("收到消息: {}", message);
                processMessage(message);
            }
        } catch (SocketException e) {
            logger.info("用户下线");
            if(this.user != null) ServerUtils.removeConnection(user.getUsername());
        }
        catch (Exception e) {
            logger.error("客户端处理异常！: {}", e.getMessage());
        }
    }

    private void processMessage(Message message) {
        Message reply = new Message();
        if(MessageType.MESSAGE_TEST.equals(message.getType())) {
            reply.setType(MessageType.MESSAGE_TEST);
            reply.setContent("Hello");
            byte[] bytes = new byte[10];
            for(int i = 0; i < 10; i++) {
                bytes[i] = (byte) i;
            }

            reply.setFileContent(bytes);
            ServerUtils.sendMessage(socket, reply);
        }

        if(MessageType.MESSAGE_REGISTER_REQUEST.equals(message.getType())) {
            User temp = new User(message.getContent());
            String uid = UidGenerator.generateUID();
            temp.setUid(uid);
            try {
                DbUser.getInstance().add(temp);
                reply.setContent(temp.toString());
                reply.setType(MessageType.MESSAGE_REGISTER_SUCCESS);
                user = temp;
                ServerUtils.addConnection(user.getUsername(), socket);
                ServerUtils.sendMessage(socket, reply);
            } catch (SQLException e) {
                reply.setType(MessageType.MESSAGE_SERVER_ERROR);
                ServerUtils.sendMessage(socket, reply);
            }
        }

        if(MessageType.MESSAGE_LOGIN_REQUEST.equals(message.getType())) {
            User temp = new User(message.getContent());
            try {
                temp = DbUser.getInstance().checkLogin(temp.getUsername(), temp.getPassword());
                reply.setContent(temp.toString());
                reply.setType(MessageType.MESSAGE_LOGIN_SUCCESS);
                ServerUtils.addConnection(temp.getUsername(), socket);
                user = temp;
                ServerUtils.sendMessage(socket, reply);
            } catch (SQLException e) {
                reply.setType(MessageType.MESSAGE_SERVER_ERROR);
                ServerUtils.sendMessage(socket, reply);
            } catch (UserNotExistException e) {
                reply.setType(MessageType.MESSAGE_LOGIN_USER_NOT_EXIST);
                ServerUtils.sendMessage(socket, reply);
            } catch (PasswordErrorException e) {
                reply.setType(MessageType.MESSAGE_LOGIN_PASSWORD_INCORRECT);
                ServerUtils.sendMessage(socket, reply);
            }
        }

        if(MessageType.MESSAGE_FILE.equals(message.getType())) {
            Path path = ServerUtils.getProjectRoot();
            path = path.resolve("images").resolve(user.getUid());
            try {
                Files.createDirectories(path);
                path = path.resolve(message.getContent());
                Files.write(path, message.getFileContent());
            } catch (IOException e) {
                logger.warn("创建文件夹异常: {}", e.getMessage());
            }
        }

        if(MessageType.MESSAGE_GET_FILE.equals(message.getType())) {
            Path path = ServerUtils.getProjectRoot();
            path = path.resolve("images").resolve(user.getUid()).resolve(message.getContent());

            try {
                reply.setFileContent(Files.readAllBytes(path));
                reply.setType(MessageType.MESSAGE_FILE);
                reply.setContent(message.getContent());
                ServerUtils.sendMessage(socket, reply);
            } catch (IOException e) {
                logger.warn("读取文件异常: {}", e.getMessage());
            }
        }

        if(MessageType.MESSAGE_GET_ALL_IMAGES.equals(message.getType())) {
            Path path = ServerUtils.getProjectRoot();
            path = path.resolve("images").resolve(user.getUid());

            try (Stream<Path> pathStream = Files.list(path)) {
                pathStream.filter(Files::isRegularFile).forEach(this::processFile);
            } catch (Exception e) {
                logger.info("读取文件夹异常:{}", e.getMessage());
            }
            reply.setType(MessageType.MESSAGE_GET_IMAGE_COMPLETE);
            ServerUtils.sendMessage(socket, reply);
        }

        if(MessageType.MESSAGE_CHECK_UNSAVED_IMAGE.equals(message.getType())) {
            if(message.getContent() == null || message.getContent().isEmpty()) {
                reply.setType(MessageType.MESSAGE_ALL_SAVED);
                ServerUtils.sendMessage(socket, reply);
                return;
            }
            Path path = ServerUtils.getProjectRoot();
            path = path.resolve("images").resolve(user.getUid());

            if(Files.notExists(path)) {
                try {
                    Files.createDirectories(path);
                } catch (IOException e) {
                    logger.warn("创建文件夹出现异常: {}", e.getMessage());
                }
            }

            String[] fileNames = Objects.requireNonNull(new File(path.toString()).list());
            String[] userFiles = message.getContent().split(" ");


            if(fileNames.length == userFiles.length) {
                reply.setType(MessageType.MESSAGE_ALL_SAVED);
                ServerUtils.sendMessage(socket, reply);
                return;
            }

            List<String> userFileList = new ArrayList<>();

            for(var i : userFiles) {
                String name = Path.of(i).getFileName().toString();
                userFileList.add(name);
            }

            List<String> files = new ArrayList<>(List.of(fileNames));
            List<String> unSavedFiles = new ArrayList<>();
            for(var i : userFileList) {
                if(!files.contains(i)) {
                    unSavedFiles.add(i);
                }
            }
            StringBuilder unSavedFilesStr = new StringBuilder();
            for(var i : unSavedFiles) {
                unSavedFilesStr.append(i);
                unSavedFilesStr.append(" ");
            }

            reply.setContent(unSavedFilesStr.toString());
            reply.setType(MessageType.MESSAGE_REQUIRE_SAVING_IMAGE);
            ServerUtils.sendMessage(socket, reply);
        }
    }

    private void processFile(Path filePath) {

        try {
            byte[] file = Files.readAllBytes(filePath);

            Message message = new Message();
            message.setContent(filePath.getFileName().toString());
            message.setType(MessageType.MESSAGE_FILE);
            message.setFileContent(file);
            ServerUtils.sendMessage(socket, message);
        } catch (IOException e) {
            logger.info("读取文件异常: {}", e.getMessage());
        }
    }

}
